// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraGameState.h"

#include "AbilitySystem/LyraAbilitySystemComponent.h"
#include "Async/TaskGraphInterfaces.h"
#include "GameFramework/GameplayMessageSubsystem.h"
#include "GameModes/LyraExperienceManagerComponent.h"
#include "Messages/LyraVerbMessage.h"
#include "Player/LyraPlayerState.h"
#include "LyraLogChannels.h"
#include "Net/UnrealNetwork.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraGameState)

class APlayerState;
class FLifetimeProperty;

extern ENGINE_API float GAverageFPS; // 外部声明的平均FPS


/**
 * 构造函数，初始化组件和属性
 */
ALyraGameState::ALyraGameState(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	PrimaryActorTick.bCanEverTick = true; // 启用每帧更新
	PrimaryActorTick.bStartWithTickEnabled = true; // 开始时就启用更新

	AbilitySystemComponent = ObjectInitializer.CreateDefaultSubobject<ULyraAbilitySystemComponent>(this, TEXT("AbilitySystemComponent")); // 创建能力系统组件
	AbilitySystemComponent->SetIsReplicated(true); // 启用复制
	AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed); // 设置复制模式为混合

	ExperienceManagerComponent = CreateDefaultSubobject<ULyraExperienceManagerComponent>(TEXT("ExperienceManagerComponent")); // 创建经验管理器组件

	ServerFPS = 0.0f; // 初始化服务器FPS
}

/**
 * 预初始化组件
 */
void ALyraGameState::PreInitializeComponents()
{
	Super::PreInitializeComponents(); // 调用父类
}

/**
 * 后初始化组件
 */
void ALyraGameState::PostInitializeComponents()
{
	Super::PostInitializeComponents(); // 调用父类

	check(AbilitySystemComponent); // 确保能力系统组件有效
	AbilitySystemComponent->InitAbilityActorInfo(/*Owner=*/ this, /*Avatar=*/ this); // 初始化能力Actor信息
}

/**
 * 获取能力系统组件
 * @return 能力系统组件
 */
UAbilitySystemComponent* ALyraGameState::GetAbilitySystemComponent() const
{
	return AbilitySystemComponent; // 返回能力系统组件
}

/**
 * Actor结束游戏时的处理
 * @param EndPlayReason 结束游戏原因
 */
void ALyraGameState::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason); // 调用父类
}

/**
 * 添加玩家状态
 * @param PlayerState 玩家状态
 */
void ALyraGameState::AddPlayerState(APlayerState* PlayerState)
{
	Super::AddPlayerState(PlayerState); // 调用父类
}

/**
 * 移除玩家状态
 * @param PlayerState 玩家状态
 */
void ALyraGameState::RemovePlayerState(APlayerState* PlayerState)
{
	//@TODO: 现在没有调用这个（只有"丰富"的AGameMode使用它，而不是AGameModeBase）
	// 至少需要注释引擎代码，并可能移动东西
	Super::RemovePlayerState(PlayerState); // 调用父类
}

/**
 * 无缝旅行过渡检查点
 * @param bToTransitionMap 是否前往过渡地图
 */
void ALyraGameState::SeamlessTravelTransitionCheckpoint(bool bToTransitionMap)
{
	// 移除非活动和机器人
	for (int32 i = PlayerArray.Num() - 1; i >= 0; i--) // 反向遍历玩家数组
	{
		APlayerState* PlayerState = PlayerArray[i]; // 获取玩家状态
		if (PlayerState && (PlayerState->IsABot() || PlayerState->IsInactive())) // 如果是机器人或非活动状态
		{
			RemovePlayerState(PlayerState); // 移除玩家状态
		}
	}
}

/**
 * 获取生命周期复制属性
 * @param OutLifetimeProps 输出生命周期属性列表
 */
void ALyraGameState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 调用父类

	DOREPLIFETIME(ThisClass, ServerFPS); // 复制服务器FPS
	DOREPLIFETIME_CONDITION(ThisClass, RecorderPlayerState, COND_ReplayOnly); // 仅在回放时复制录制器玩家状态
}

/**
 * 每帧更新
 * @param DeltaSeconds 帧时间差
 */
void ALyraGameState::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds); // 调用父类

	if (GetLocalRole() == ROLE_Authority) // 如果在权威端
	{
		ServerFPS = GAverageFPS; // 更新服务器FPS
	}
}

/**
 * 多播消息到客户端（不可靠）
 * @param Message 动词消息
 */
void ALyraGameState::MulticastMessageToClients_Implementation(const FLyraVerbMessage Message)
{
	if (GetNetMode() == NM_Client) // 如果在客户端
	{
		UGameplayMessageSubsystem::Get(this).BroadcastMessage(Message.Verb, Message); // 广播消息
	}
}

/**
 * 多播消息到客户端（可靠）
 * @param Message 动词消息
 */
void ALyraGameState::MulticastReliableMessageToClients_Implementation(const FLyraVerbMessage Message)
{
	MulticastMessageToClients_Implementation(Message); // 调用不可靠版本
}

/**
 * 获取服务器FPS
 * @return 服务器FPS
 */
float ALyraGameState::GetServerFPS() const
{
	return ServerFPS; // 返回服务器FPS
}

/**
 * 设置录制器玩家状态
 * @param NewPlayerState 新的玩家状态
 */
void ALyraGameState::SetRecorderPlayerState(APlayerState* NewPlayerState)
{
	if (RecorderPlayerState == nullptr) // 如果录制器玩家状态为空
	{
		// 设置它并调用复制回调，以便它可以进行任何录制时设置
		RecorderPlayerState = NewPlayerState; // 设置录制器玩家状态
		OnRep_RecorderPlayerState(); // 调用复制回调
	}
	else // 如果已经设置过
	{
		UE_LOG(LogLyra, Warning, TEXT("SetRecorderPlayerState was called on %s but should only be called once per game on the primary user"), *GetName()); // 记录警告
	}
}

/**
 * 获取录制器玩家状态
 * @return 录制器玩家状态
 */
APlayerState* ALyraGameState::GetRecorderPlayerState() const
{
	// TODO: 如果为空，也许自动选择它？

	return RecorderPlayerState; // 返回录制器玩家状态
}

/**
 * 录制器玩家状态复制回调
 */
void ALyraGameState::OnRep_RecorderPlayerState()
{
	OnRecorderPlayerStateChangedEvent.Broadcast(RecorderPlayerState); // 广播录制器玩家状态更改事件
}